#pragma once

#include <array>

template<class T, int cap>
class RingQueue {
public:
    static constexpr int realcap = cap + 1;
    using Array = std::array<T, realcap>;

    T &Push(const T& t)
    {
        if (front_ == (back_ + 1) % realcap) {
            front_ = (front_ + 1) % realcap;
        }
        queue_[back_++] = t;
        back_ %= realcap;
        return queue_[(back_ + cap) % realcap];
    }

    void Clear()
    {
        front_ = 0;
        back_ = 0;
    }

    class Iter {
    public:
        Iter(Array *ptr, int offset)
            : ptr_(ptr), offset_(offset)
        {
        }

        Iter &operator++()
        {
            offset_ = (offset_ + 1) % realcap;
            return *this;
        }

        Iter operator++(int)
        {
            auto ret = *this;
            offset_ = (offset_ + 1) % realcap;
            return ret;
        }

        T &operator*()
        {
            return (*ptr_)[offset_];
        }

        T *operator->()
        {
            return &(*ptr_)[offset_];
        }

        bool operator==(const Iter &rhs)
        {
            return offset_ == rhs.offset_;
        }

        bool operator!=(const Iter &rhs)
        {
            return offset_ != rhs.offset_;
        }

    private:
        Array *ptr_;
        int offset_;
    };

    class RevertIter {
    public:
        RevertIter(Array *ptr, int offset)
            : ptr_(ptr), offset_(offset)
        {
        }

        RevertIter &operator++()
        {
            offset_ = (offset_ + cap) % realcap;
            return *this;
        }

        RevertIter operator++(int)
        {
            auto ret = *this;
            offset_ = (offset_ + cap) % realcap;
            return ret;
        }

        T &operator*()
        {
            return (*ptr_)[offset_];
        }

        T *operator->()
        {
            return &(*ptr_)[offset_];
        }

        bool operator==(const RevertIter &rhs)
        {
            return offset_ == rhs.offset_;
        }

        bool operator!=(const RevertIter &rhs)
        {
            return offset_ != rhs.offset_;
        }

    private:
        Array *ptr_;
        int offset_;
    };

    Iter begin()
    {
        return Iter(&queue_, front_);
    }

    Iter end()
    {
        return Iter(&queue_, back_);
    }

    RevertIter rbegin()
    {
        return RevertIter(&queue_, (back_ + cap) % realcap);
    }

    RevertIter rend()
    {
        return RevertIter(&queue_, (front_ + cap) % realcap);
    }

private:
    Array queue_;
    int front_ = 0;
    int back_ = 0;
};
